package org.example.springboot_download_demo;

import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

@RestController
public class DownloadController {

    private String FILE_DIR = "/";

    @GetMapping("/simpleDownload")
    public ResponseEntity<Resource> simpleDownload() {
        String fileName = "CMakeCache.txt";
        Path path = Paths.get(FILE_DIR).resolve(fileName).normalize();
        try {
            Resource resource = new UrlResource(path.toUri());
            if (resource.exists() && resource.isReadable()) {
                return ResponseEntity.ok()
                        .contentType(MediaType.APPLICATION_OCTET_STREAM)
                        .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")
                        .body(resource);
            }else {
                return ResponseEntity.notFound().build();
            }
        } catch (MalformedURLException e) {
            return ResponseEntity.status(500).build();
        }
    }

    @GetMapping("/simpleDownloadStream")
    public String simpleDownloadStream(HttpServletResponse response) {
        String fileName = "/test_workspace/elasticsearch-8.6.2-windows-x86_64.zip";
        File file = new File(fileName);
        if(!file.exists()){
            return "下载文件不存在";
        }
        response.reset();
        response.setContentType(String.valueOf(MediaType.APPLICATION_OCTET_STREAM));
        response.setCharacterEncoding("utf-8");
        response.setContentLength((int) file.length());
        response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + "elasticsearch-8.6.2-windows-x86_64.zip" );

        try(BufferedInputStream bis = new BufferedInputStream(Files.newInputStream(file.toPath()));
            OutputStream os  = response.getOutputStream();) {
            byte[] buff = new byte[1024];
            int i = 0;
            while ((i = bis.read(buff)) != -1) {
                os.write(buff, 0, i);
                os.flush();
            }
        } catch (IOException e) {
            return "下载失败";
        }
        return "下载成功";
    }

    @GetMapping("/streamDownload")
    public ResponseEntity<StreamingResponseBody> streamDownload() {
        String fileDir = "/test_workspace";
        String fileName = "elasticsearch-8.6.2-windows-x86_64.zip";
        File file = new File(fileDir, fileName);
        if(!file.exists()){
            return ResponseEntity.notFound().build();
        }
        StreamingResponseBody responseBody = outputStream -> {
            try (FileInputStream inputStream = new FileInputStream(file)) {
                byte[] buffer = new byte[1024 * 8]; // 8KB 缓冲区
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                    outputStream.flush(); // 确保数据即时写出
                }
            }
        };
        String contentDisposition = "attachment; filename=\"" + fileName + "\"";
        return ResponseEntity.ok()
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .header(HttpHeaders.CONTENT_DISPOSITION, contentDisposition)
                .body(responseBody);
    }

    @GetMapping("/streamMsg")
    public ResponseBodyEmitter streamMsg() {
        ResponseBodyEmitter emitter = new ResponseBodyEmitter();
        // 模拟一个耗时任务
        new Thread(() -> {
            try {
                for (int i = 1; i <= 100; i ++) {
                    // 向客户端发送进度
                    emitter.send("" + i);
                    Thread.sleep(100); // 模拟任务耗时
                }
                emitter.complete(); // 任务完成，关闭连接
            } catch (Exception e) {
                emitter.completeWithError(e); // 出现异常时通知客户端
            }
        }).start();
        emitter.onTimeout(emitter::complete);
        return emitter; // 返回 Emitter
    }
}
